/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;

/**
 *
 * @author Ivan
 */
public abstract class AEntityContentProvider<T> {

    private Class<T> entityClass;
    private String nameTable;
    private String idEntityAttr;
    private Object idEntityValue;
    private Map<String, Object> entityContent;

    protected AEntityContentProvider(Class<T> entityClass) {

        initialize(entityClass);
    }

    public void initialize(Class<T> entityClass){
        this.entityClass = entityClass;
        entityContent = new HashMap<String, Object>();
    }
    
    protected AEntityContentProvider() {
    }

    public Object[] getAllAttributesNames() {

        List<String> allAttributesNames = new ArrayList<String>();
        Set<Map.Entry<String, Object>> entries = entityContent.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            allAttributesNames.add(entry.getKey());
        }
        return allAttributesNames.toArray();
    }

    public Map<String, Object> getEntityContent() {
        return entityContent;
    }

    public String getNameTable() {
        return nameTable;
    }

    public String getIdEntityAttr() {
        return idEntityAttr;
    }

    public Object getIdEntity() {
        return idEntityValue;
    }

    
    public void reflect() throws IllegalAccessException, SecurityException {

        //reflect name of source table
        for (int i = 0; i < entityClass.getDeclaredAnnotations().length; i++) {
            Annotation annotation = entityClass.getDeclaredAnnotations()[i];
            if (annotation instanceof Table) {
                nameTable = ((Table) annotation).name();
                break;
            }
        }

        //reflect names amd values of fields
        for (int i = 0; i < entityClass.getDeclaredFields().length; i++) {
            Field field = entityClass.getDeclaredFields()[i];

            for (int j = 0; j < field.getDeclaredAnnotations().length; j++) {

                Annotation annotation = field.getDeclaredAnnotations()[j];

                if (annotation instanceof Column) {
                    field.setAccessible(true);

                    idEntityAttr = ((Column) annotation).name();

                    entityContent.put(((Column) annotation).name(), field.get(this));
                } else if (annotation instanceof Id) {
                    field.setAccessible(true);
                    idEntityValue = field.get(this);
                    break;
                } else if (annotation instanceof JoinColumn) {
                    field.setAccessible(true);
                    String attributeName = ((JoinColumn) annotation).name();
                    Object refEntity = field.get(this);
                    Object fieldRefValue = null;
                    if (refEntity != null) {

                        boolean isFoundedRefValue = false;
                        for (int k = 0; k < refEntity.getClass().getDeclaredFields().length; k++) {
                            Field fieldRefEntity = refEntity.getClass().getDeclaredFields()[k];
                            for (int l = 0; l < fieldRefEntity.getDeclaredAnnotations().length; l++) {
                                Annotation annotationRefEntity = fieldRefEntity.getDeclaredAnnotations()[l];
                                if (annotationRefEntity instanceof Id) {
                                    fieldRefEntity.setAccessible(true);
                                    fieldRefValue = field.get(this);
                                    isFoundedRefValue = true;
                                    break;
                                }

                            }
                            if (isFoundedRefValue) {
                                break;
                            }
                        }

                        for (int l = 0; l < fieldRefValue.getClass().getDeclaredFields().length; l++) {
                            Field fieldID = fieldRefValue.getClass().getDeclaredFields()[l];
                            for (int m = 0; m < fieldID.getDeclaredAnnotations().length; m++) {
                                Annotation annotationID = fieldID.getDeclaredAnnotations()[m];
                                if (annotationID instanceof Id) {
                                    fieldID.setAccessible(true);
                                    fieldRefValue = fieldID.get(fieldRefValue);
                                    break;
                                }
                            }
                        }

                    }
                    entityContent.put(attributeName, fieldRefValue);
                }

            }
        }
    }
}
